﻿using UnityEngine;
using System.Collections;
using Dict.Config;
using Dict.Blo;
using Dict.DataModel;
using System.Collections.Generic;
using System;
using ProtoBuf.Message;

namespace UI
{
    public class UIHero
    {
        #region 字典数据
        public Dict.DataModel.TableHero heroData;
        private BaseAttributeData defaultAttribtue;
        private BaseAttributeData growUpAttribtue;      //只受天赋升阶影响
        #endregion

        #region 总体属性

        private BaseAttributeData currentAttribute;
        private BaseAttributeData currentPercentAttribute;
        /// <summary>
        /// 技能
        /// </summary>
        public UISkill[] Skills
        {
            get
            {
                if (skills == null)
                {
                    GenerateData();
                }
                return skills;
            }
        }
        private UISkill[] skills = null;
        public string skillOrder;
        private OrderDictionary<string, UITalent> talentData = null;

        private bool inited = false;
        private bool dirty = true;
        /// <summary>
        /// 天赋
        /// </summary>
        public OrderDictionary<string, UITalent> TalentData
        {
            get
            {
                if (dirty)
                {
                    ResetAttribute();
                }
                return talentData;
            }
        }
        public UITalent CurrentTalent
        {
            get
            {
                if(dirty)
                {
                    ResetAttribute();
                }
                if (talentData == null || !talentData.ContainsKey(talentLevel.ToString()))
                {
                    return null;
                }
                return talentData[talentLevel.ToString()];
            }
        }

        public UITalent NextTalent
        {
            get
            {
                if (TalentData == null || !TalentData.ContainsKey((talentLevel + 1).ToString()))
                {
                    return null;
                }
                return TalentData[(talentLevel + 1).ToString()];
            }
        }

        public int talentLevel;//天赋解锁数量
        public List<string> talentBranch = new List<string>();//分支天赋

        public List<FriendBuffer> BufferForOther
        {
            get
            {
                if(bufferForOther == null)
                {
                    ResetAttribute();
                }
                return bufferForOther;
            }
        }

        private List<FriendBuffer> bufferForOther = null;
        
        #endregion

        public string heroId;
        public string guid;
        private int m_level;//等级
        private long m_exp;//经验

        public int breachlevel;//突破等级
        public int breachExp;//突破经验
        public string breachLastAddExpTime;//上次吃经验时间
        private BaseAttributeData breachPercentData;//提供的百分比加成
        private Training trainingData;
        private Training tempTrainingData;
        
        public bool Help()
        {
            var helps = StaticData.playerData.InstPlayerData.GetHelpCamps();
            foreach(var help in helps)
            {
                if(!string.IsNullOrEmpty(guid) && help.Value.guid == guid)
                {
                    return true;
                }
            }

            return false;
        }


        
        #region 辅助
        public UIHeroFormation owner;
        public UIInstPlayerData simplePlayer;
        #region 训练
        private BaseAttributeData training;//训练属性
        private BaseAttributeData tempTraining;//训练临时属性
        #endregion

        #region 激活天赋
        private BaseAttributeData talentAttribute;
        private BaseAttributeData talentPercentAttribute;

        #endregion
        #region 料理加成
        private BaseAttributeData cookAttribute;
        #endregion
        /// <summary>
        /// 英雄等级
        /// </summary>
        public int level
        {
            get
            {
                if (IsUserHero)
                {
                    return StaticData.playerData.level;
                }
                return m_level;
            }
        }

        /// <summary>
        /// 英雄经验
        /// </summary>
        public long exp
        {
            get
            {
                if (IsUserHero)
                {
                    return StaticData.playerData.exp;
                }
                return m_exp;
            }
        }
        /// <summary>
        /// 英雄名称
        /// </summary>
        public string heroName
        {
            get
            {
                if (heroData.heroClass == (int)HeroClass.Main_Actor_Man || heroData.heroClass == (int)HeroClass.Main_Actor_Woman)
                {
                    return StaticData.playerData.name;
                }
                else
                {
                    return TableTextBlo.GetText(this.heroData.name);
                }
            }
        }

        /// <summary>
        /// 是否为主角
        /// </summary>
        public bool IsUserHero
        {
            get
            {
                return guid == StaticData.playerData.heroWarUID;
            }
        }
        #endregion

        #region 初始化
        public UIHero(string heroId)
        {
            this.heroId = heroId;
            heroData = DictHeroBlo.GetTableHero(heroId);
            if (heroData == null)
            {
                throw new System.NullReferenceException("heroId:" + heroId);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="clone"></param>
        public UIHero(UIHero clone)
        {
            this.heroId = clone.heroId;
            heroData = DictHeroBlo.GetTableHero(clone.heroId);
            guid = clone.guid;
            m_level = clone.m_level;
            m_exp = clone.m_exp;
            talentLevel = clone.talentLevel;
            talentBranch.Clear();
            foreach (var i in clone.talentBranch)
            {
                talentBranch.Add(i);
            }
            skillOrder = clone.skillOrder;
            trainingData = clone.trainingData;
            tempTrainingData = clone.tempTrainingData;
            
            breachlevel = clone.breachlevel;
            breachExp = clone.breachExp;
            breachLastAddExpTime = clone.breachLastAddExpTime;
            
            dirty = true;
        }

        /// <summary>
        /// 网络数据
        /// </summary>
        /// <param name="data"></param>
        public void InitData(ProtoBuf.Message.Warrior data)
        {
            guid = data.guid;
            m_level = data.level;
            m_exp = data.exp;
            talentLevel = data.talent;
            talentBranch.Clear();
            foreach (var i in data.talentBranch)
            {
                talentBranch.Add(i);
            }
            skillOrder = data.skillOrder;
            trainingData = data.training;
            tempTrainingData = data.tempTraining;
            if (data.breached != null)
            {
                breachlevel = data.breached.level;
                breachExp = data.breached.exp;
                breachLastAddExpTime = data.breached.lastAddExpTime;
            }
            dirty = true;

            if (cookAttribute == null)
                cookAttribute = new BaseAttributeData(0);
            if(data.cooking != null)
            {
                cookAttribute.Reset();
                cookAttribute = new BaseAttributeData(data.cooking.prop);
            }

            //GenerateData();
        }
        
        /// <summary>
        /// 其他玩家
        /// </summary>
        /// <param name="data"></param>
        public void InitData(ProtoBuf.Message.WarriorSimpleInfo data)
        {
            m_level = data.level;
            heroId = data.heroId;
            breachlevel = data.breachedLevel;
            talentLevel = data.talent;

            currentAttribute = new BaseAttributeData(data.baseProp);

            inited = true;
            skills = new UISkill[3];
            SetSkillData();
        }

        public void GenerateData()
        {
            if (inited)
            {
                return;
            }
            inited = true;
            this.currentAttribute = new BaseAttributeData(0);
            this.currentPercentAttribute = new BaseAttributeData(0);
            growUpAttribtue = new BaseAttributeData(0);
            talentAttribute = new BaseAttributeData(0);
            talentPercentAttribute = new BaseAttributeData(0);
            bufferForOther = new List<FriendBuffer>();
            training = new BaseAttributeData(0);
            tempTraining = new BaseAttributeData(0);
            breachPercentData = new BaseAttributeData(0);
            skills = new UISkill[3];
            SetBaseProp();
            SetSkillData();
            GenerateTalent();

           
            //FreshLuckData();
        }

        private void GenerateTalent()
        {
            List<TableTalentAdvenced> tts = DictTalentAdvancedBlo.GetTalentByHero(heroId);
            talentData = new OrderDictionary<string, UITalent>();
            for (int i = 0; i < tts.Count; ++i)
            {
                UITalent ut = new UITalent(tts[i], this);
                talentData.Add(tts[i].talentLevel, ut);
            }
        }
        

        private void SetBaseProp()
        {
            defaultAttribtue = new BaseAttributeData(0);
            defaultAttribtue.SetProp(AttributeQueue.Attack, heroData.attBase);
            defaultAttribtue.SetProp(AttributeQueue.Hp, heroData.hpBase);
            defaultAttribtue.SetProp(AttributeQueue.PhyDefend, heroData.pdefBase);
            defaultAttribtue.SetProp(AttributeQueue.MagicDefend, heroData.mdefBase);
            defaultAttribtue.SetProp(AttributeQueue.cri, heroData.cri);
            defaultAttribtue.SetProp(AttributeQueue.antiCri, heroData.antiCri);
            defaultAttribtue.SetProp(AttributeQueue.hit, heroData.hit);
            defaultAttribtue.SetProp(AttributeQueue.dodge, heroData.dodge);
            defaultAttribtue.SetProp(AttributeQueue.damageAdd, heroData.damageAdd);
            defaultAttribtue.SetProp(AttributeQueue.damageReduce, heroData.damageReduce);
            defaultAttribtue.SetProp(AttributeQueue.criFactor, heroData.criFactor);
        }

        public double GetDefaultPerProp()
        {
            double v = defaultAttribtue.GetProp(AttributeQueue.cri);
            v+= defaultAttribtue.GetProp(AttributeQueue.antiCri);
            v+= defaultAttribtue.GetProp(AttributeQueue.hit);
            v+= defaultAttribtue.GetProp(AttributeQueue.dodge);
            v += defaultAttribtue.GetProp(AttributeQueue.damageAdd);
            v += defaultAttribtue.GetProp(AttributeQueue.damageReduce);
            v += defaultAttribtue.GetProp(AttributeQueue.criFactor);
            return v;
        }

        private void SetSkillData()
        {
            for (int i = 0; i < heroData.SkillId_array.Length; i++)
            {
                if (DictHeroSkillBlo.GetTalbeSkill(heroData.SkillId_array[i]) != null)
                {
                    Skills[i] = new UISkill();
                    Skills[i].InitData(heroData.SkillId_array[i], i);
                }
            }
            if (DictHeroSkillBlo.GetTalbeSkill(heroData.UltSkillId) != null)
            {
                Skills[2] = new UISkill();
                Skills[2].InitData(heroData.UltSkillId, 2);
            }
            //技能发动顺序
            if (skillOrder != null && skillOrder.Length > 0)
            {
                string[] sos = skillOrder.Split(',');
                for (int i = 0; i < sos.Length; i++)
                {
                    if (i < 2)
                    {
                        UpdateSkillIndex(sos[i], i);
                    }
                }
            }
        }

        private void UpdateTrainningData()
        {
            if (trainingData != null)
            {
                training.SetProp(AttributeQueue.Hp, trainingData.hp);
                training.SetProp(AttributeQueue.Attack, trainingData.att);
                training.SetProp(AttributeQueue.PhyDefend, trainingData.pdef);
                training.SetProp(AttributeQueue.MagicDefend, trainingData.mdef);
            }
            if (tempTrainingData != null)
            {
                tempTraining.SetProp(AttributeQueue.Hp, tempTrainingData.hp);
                tempTraining.SetProp(AttributeQueue.Attack, tempTrainingData.att);
                tempTraining.SetProp(AttributeQueue.PhyDefend, tempTrainingData.pdef);
                tempTraining.SetProp(AttributeQueue.MagicDefend, tempTrainingData.mdef);
            }

        }

        private void UpdateBreachedData()
        {
            Dict.DataModel.TableHeroBreached tableBreach = DictHeroBreachBlo.GetTableHeroBreached(breachlevel);
            if (tableBreach != null)
            {
                breachPercentData.SetProp(AttributeQueue.Attack, tableBreach.AttAddPercent * CommonMethod.tableAttributeConvert);
                breachPercentData.SetProp(AttributeQueue.PhyDefend, tableBreach.PDefAddPercent * CommonMethod.tableAttributeConvert);
                breachPercentData.SetProp(AttributeQueue.MagicDefend, tableBreach.MDefAddPercent * CommonMethod.tableAttributeConvert);
                breachPercentData.SetProp(AttributeQueue.Hp, tableBreach.HpAddPercent * CommonMethod.tableAttributeConvert);
            }
        }

        private void UpdateTalentAttribtue()
        {
            foreach (var t in talentData)
            {
                if (t.IsTrunk)
                {
                    if (talentLevel >= int.Parse(t.data.talentLevel))
                    {
                        t.isUnlocked = true;
                        t.isActived = true;
                    }
                    else if (int.Parse(t.data.talentLevel) == talentLevel + 1)
                    {
                        t.isUnlocked = true;
                        t.isActived = false;
                    }
                    else
                    {
                        t.isUnlocked = false;
                        t.isActived = false;
                    }
                }
                else
                {
                    if(talentBranch != null && talentBranch.Contains(t.data.talentLevel))
                    {
                        t.isActived = true;
                        t.isUnlocked = true;
                    }
                    else
                    {
                        t.isActived = false;
                        //if (!string.IsNullOrEmpty(t.data.parent) && !talentData[t.data.parent].isActived
                        //|| !string.IsNullOrEmpty(t.data.parent2) && !talentData[t.data.parent2].isActived)
                        //{
                        //    t.isUnlocked = false;
                        //}
                        //else
                        //{
                        //    t.isUnlocked = true;
                        //}
                        if (!string.IsNullOrEmpty(t.data.parent) && talentData[t.data.parent].isActived && talentData[t.data.parent].IsTrunk
                        || !string.IsNullOrEmpty(t.data.parent2) && talentData[t.data.parent2].isActived && talentData[t.data.parent2].IsTrunk)
                        {
                            t.isUnlocked = true;
                        }
                        else
                        {
                            t.isUnlocked = false;
                        }
                    }
                    
                }
            }

            bufferForOther.Clear();
            talentAttribute.Reset();
            talentPercentAttribute.Reset();
            growUpAttribtue.Reset();

            if (CurrentTalent != null)
            {
                growUpAttribtue.AddProp(AttributeQueue.Attack, CurrentTalent.data.attGrow);
                growUpAttribtue.AddProp(AttributeQueue.Hp, CurrentTalent.data.hpGrow);
                growUpAttribtue.AddProp(AttributeQueue.PhyDefend, CurrentTalent.data.pdefGrow);
                growUpAttribtue.AddProp(AttributeQueue.MagicDefend, CurrentTalent.data.mdefGrow);
            }
            foreach (var td in TalentData)
            {
                if(td.isActived)
                {
                    talentAttribute.AddProp(AttributeQueue.Attack, td.data.attConstAdd);
                    talentAttribute.AddProp(AttributeQueue.Hp, td.data.hpConstAdd);
                    talentAttribute.AddProp(AttributeQueue.PhyDefend, td.data.pdefConstAdd);
                    talentAttribute.AddProp(AttributeQueue.MagicDefend, td.data.mdefConstAdd);
                    if (td.TalentSkill != null)
                    {
                        bufferForOther.AddRange(td.CaculateSkillProperty(talentAttribute, talentPercentAttribute));
                    }
                }
            }
        }

        #endregion
        #region 数据变更
        /// <summary>
        /// 更新英雄等级
        /// </summary>
        /// <param name="addLev"></param>
        public void AddLevel(int addLev)
        {

            m_level += addLev;
            ResetAttribute();
        }


        public void GetTalentChangeAttribute(string mayGetTalent,out BaseAttributeData currentAtt,out BaseAttributeData nextAtt)
        {
            if(TalentData.ContainsKey(mayGetTalent))
            {
                UITalent talent = talentData[mayGetTalent];
                if(talent.IsTrunk)
                {
                    int realyLevel = talentLevel;
                    talentLevel = int.Parse(talent.data.talentLevel);
                    ResetAttribute();
                    nextAtt = new BaseAttributeData(CurrentAttribute);
                    talentLevel = realyLevel;
                    ResetAttribute();
                    currentAtt = new BaseAttributeData(CurrentAttribute);
                }
                else
                {
                    talentBranch.Add(mayGetTalent);
                    ResetAttribute();
                    nextAtt = new BaseAttributeData(CurrentAttribute);
                    talentBranch.Remove(mayGetTalent);
                    ResetAttribute();
                    currentAtt = new BaseAttributeData(CurrentAttribute);
                }
            }
            else
            {
                currentAtt = new BaseAttributeData(CurrentAttribute);
                nextAtt = BaseAttributeData.zero;
                Debug.LogError("Talent id not exist");

            }
        }

        /// <summary>
        /// 更新英雄培养信息
        /// </summary>
        /// <param name="training"></param>
        /// <param name="tempTraining"></param>
        public void RefreshTraingData(ProtoBuf.Message.Training training, ProtoBuf.Message.Training tempTraining)
        {
            this.trainingData = training;
            this.tempTrainingData = tempTraining;
            ResetAttribute();
        }

        /// <summary>
        /// 更新英雄突破信息
        /// </summary>
        /// <param name="breached"></param>
        public void RefreshBreakData(ProtoBuf.Message.Breached breached)
        {
            if (breached != null)
            {
                breachlevel = breached.level;
                breachExp = breached.exp;
                breachLastAddExpTime = breached.lastAddExpTime;
            }
            ResetAttribute();
        }

        /// <summary>
        /// 更新技能顺序
        /// </summary>
        /// <param name="skillId"></param>
        /// <param name="skillIndex"></param>
        public void UpdateSkillIndex(string skillId, int skillIndex)
        {
            foreach (var skillData in Skills)
            {
                if (Skills != null && skillData != null)
                {
                   // Debug.Log(skillData.skillData.SkillId);
                    if (skillData.skillData.SkillId == skillId)
                    {
                        skillData.UpdateSkillIndex(skillIndex);
                        return;
                    }
                }
            }
            //ResetAttribute();
        }

        public void ResetAttribute()
        {
            if(!inited)
            {
                GenerateData();
            }
            dirty = false;


            UpdateTalentAttribtue();
            UpdateTrainningData();
            UpdateBreachedData();

            currentAttribute.Reset();
            currentAttribute.AddProp(growUpAttribtue);
            currentAttribute.Multiply((level - 1));
            currentAttribute.AddProp(defaultAttribtue);
            currentAttribute.AddProp(training);
            //Debug.Log("hero talent id" + heroId + " " + talentAttribute);
            currentAttribute.AddProp(talentAttribute);
            if(cookAttribute != null)
                currentAttribute.AddProp(cookAttribute);

            currentPercentAttribute.Reset();
            currentPercentAttribute.AddProp(breachPercentData);
            //Debug.Log("hero talent percent id" + heroId + " " + talentPercentAttribute);
            currentPercentAttribute.AddProp(talentPercentAttribute);
           
            //if (board)
            //{
            //    DataMessageTool.AddMessage(DataMessage.INST_DATA_ATTRIBUTE_UPDATE, new object[] { this.guid, this.heroId });
            //}
        }
        #endregion


        #region Tool

        /// <summary>
        /// UIHero是否被培养过
        /// </summary>
        /// <returns></returns>
        public bool IsZeroHero()
        {
            if (level == 1 &&                   // 没升级过
                talentLevel == 0 &&             // 没加过天赋
                breachlevel == 1 &&             // 没突破过
                Trainning.IsZero() && TempTrainning.IsZero())       // 没训练过
            {
                return true;
            }
            return false;
        }
        
        public double GetPorp(AttributeQueue propId)
        {
            if(dirty)
            {
                ResetAttribute();
            }
            return currentAttribute.GetProp(propId) * (1 + currentPercentAttribute.GetProp(propId));
        }

        /// <summary>
        /// 常量值
        /// </summary>
        /// <param name="prop"></param>
        /// <returns></returns>
        public double GetAbs(AttributeQueue propId)
        {
            if (dirty)
            {
                ResetAttribute();
            }
            return currentAttribute.GetProp(propId);
        }
        public BaseAttributeData CurrentAttribute
        {
            get
            {
                if (dirty)
                {
                    ResetAttribute();
                }
                return currentAttribute;
            }
        }

        /// <summary>
        /// 百分比加成值
        /// </summary>
        /// <param name="propId"></param>
        /// <returns></returns>
        public double GerPorpAddPercent(AttributeQueue propId)
        {
            if (dirty)
            {
                ResetAttribute();
            }
            return currentPercentAttribute.GetProp(propId);
        }
        public BaseAttributeData CurrentPercentAttribute
        {
            get
            {
                if (dirty)
                {
                    ResetAttribute();
                }
                return currentPercentAttribute;
            }
        }
        public BaseAttributeData Trainning
        {
            get
            {
                if (dirty)
                {
                    ResetAttribute();
                }
                return training;
            }
        }
        public BaseAttributeData TempTrainning
        {
            get
            {
                if (dirty)
                {
                    ResetAttribute();
                }
                return tempTraining;
            }
        }

        public long GetHeroProvideExp()
        {
            long exp = DictHeroExpBlo.GetHeroExpToLevel(heroData.quality, level);

            return exp + m_exp + heroData.expBase;
        }

        public long GetHeroSellPrice()
        {
            long exp = DictHeroExpBlo.GetHeroExpToLevel(heroData.quality, level);

            return exp + m_exp + heroData.selloutPrice;
        }

        public string GetHeroSpaceName()
        {
            switch (heroData.space)
            {
                case 1:
                    return TableTextBlo.GetText("world_label_sao");
                case 2:
                    return TableTextBlo.GetText("world_label_alo");
                case 3:
                    return TableTextBlo.GetText("world_label_ggo"); 
            }

            return "-";
        }

        #endregion
    }
}